package com.sojoys.artifact.third.activemq;

import java.util.HashMap;
import java.util.Map;

import javax.jms.BytesMessage;
import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.MessageProducer;
import javax.jms.Session;

import org.apache.commons.collections4.MapUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import org.springframework.cglib.reflect.FastClass;
import org.springframework.cglib.reflect.FastMethod;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.jms.listener.SessionAwareMessageListener;
import org.springframework.jms.support.converter.MessageConverter;

import com.sojoys.artifact.annotation.RemoteServer;
import com.sojoys.artifact.third.rpc.util.SerializationUtil;

import javassist.util.proxy.ProxyFactory;


/**
 * 消息监听
 * 
 * @author win7
 *
 */
@SuppressWarnings("rawtypes")
public class ActiveMQMessageListener implements SessionAwareMessageListener, ApplicationContextAware {
	
	MessageConverter messageConverter;

	Map<String, Object> handlerMap = new HashMap<String, Object>();

	static final Logger log = LoggerFactory.getLogger(ActiveMQMessageListener.class);
	
	//代理对象
    ProxyFactory factory = new ProxyFactory();
	
	

	public MessageConverter getMessageConverter() {
		return messageConverter;
	}

	public void setMessageConverter(MessageConverter messageConverter) {
		this.messageConverter = messageConverter;
	}

	@Override
	public void setApplicationContext(ApplicationContext ctx) throws BeansException {
		//注册服务器接口
		Map<String, Object> serviceBeanMap = ctx.getBeansWithAnnotation(RemoteServer.class);
		if (MapUtils.isNotEmpty(serviceBeanMap)) {
			for (Object serviceBean : serviceBeanMap.values()) {
				RemoteServer remoteServer = serviceBean.getClass().getAnnotation(RemoteServer.class);
				String serviceName = remoteServer.value().getName();
				handlerMap.put(serviceName, serviceBean);
			}
		}
	}

	@Override
	public void onMessage(Message message, Session session) throws JMSException {
		ActiveMQResponse response = new ActiveMQResponse();
		Object result = null;
		ActiveMQRequest msg = null;
		try {
			// 解码
			msg = (ActiveMQRequest) messageConverter.fromMessage(message);
			result = handle(msg);
		} catch (Exception e) {
			log.error(msg.toString(),e);
			response.setException(e);
		}
		if (msg.isReceive()) {
			try {
				callback(message, session, response, result, msg);	
			} catch (Exception e) {
				log.error(msg.toString(),e);
			}
		}
	}

	private void callback(Message message, Session session, ActiveMQResponse response, Object result, ActiveMQRequest msg)
			throws JMSException {
		response.setResult(result);
		response.setRequestId(msg.getId());
		MessageProducer producer = session.createProducer(message.getJMSReplyTo());
		BytesMessage byteMsg = session.createBytesMessage();
		byteMsg.writeBytes(SerializationUtil.serialize(response));
		producer.send(byteMsg);
	}

	private Object handle(ActiveMQRequest msg) throws Exception {
		String serviceName = msg.getInterfaceName();

		Object serviceBean = handlerMap.get(serviceName);
		if (serviceBean == null) {
			throw new RuntimeException(String.format("can not find service bean by key: %s", serviceName));
		}
		// 获取反射调用所需的参数
		Class<?> serviceClass = serviceBean.getClass();
		String methodName = msg.getMethodName();
		Class<?>[] parameterTypes = msg.getParameterTypes();
		Object[] parameters = msg.getParameters();

//		// 执行反射调用
//		Method method = serviceClass.getMethod(methodName, parameterTypes);
//		method.setAccessible(true);
//		return method.invoke(serviceBean, parameters);

		 // 使用 CGLib 执行反射调用
		 FastClass serviceFastClass = FastClass.create(serviceClass);
		 FastMethod serviceFastMethod = serviceFastClass.getMethod(methodName,
		 parameterTypes);
		 return serviceFastMethod.invoke(serviceBean, parameters);
	}
}